<template>
  <div class="panel right-panel" :style="{width: width + 'px'}" v-show="true">
    <div class="ai-header">AI助手</div>

    <div class="ai-chat">
      <div class="chat-message-wrapper" v-for="msg in chatMessages" :key="msg.id">
        <div :class="['chat-message', 'message-' + msg.type]">
          <strong>{{ msg.type === 'user' ? '你' : 'AI' }}：</strong>
          <div class="message-content" v-html="formatMessage(msg.content)"></div>
        </div>
      </div>
      <div v-if="streamError" class="stream-error-message">
        {{ streamError }}
      </div>
    </div>

    <el-button @click="closePanel" class="button-right-close">
      关闭
    </el-button>

    <div class="panel-content">
      <div class="ai-input">
        <div class="input-group">
          <el-select v-model="modelSel" placeholder="模型切换" size="small"
                     class="custom-change-btn">
            <el-option label="DeepSeek" value="deepseek-ai/DeepSeek-V3"
                       :key="'deepseek-ai/DeepSeek-V3'"></el-option>
            <el-option label="通义千问" value="Qwen/Qwen3-8B" :key="'Qwen/Qwen3-8B'"></el-option>
          </el-select>
          <el-input
            v-model="chatInput"
            placeholder="输入问题..."
            clearable
            ref="inputRef"
            class="custom-input"
            @keyup.enter="isStreaming ? null : toggleStream()"
            :disabled="isStreaming"
          />
          <button
            @click="toggleStream"
            class="stream-action-button"
            :class="{ 'streaming': isStreaming }"
            :title="isStreaming ? '停止对话' : '发送消息'"
            ref="streamButtonRef"
          >
            <span v-if="!isStreaming"  white-space: pre-wrap>
              <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24"
                   fill="currentColor"><path d="M2.01 21L23 12 2.01 3 2 10l15 2-15 2z"></path></svg>
            </span>
            <span v-else  white-space: pre-wrap>
              <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24"
                   fill="currentColor"><path d="M6 18h12V6H6v12zM8 8h8v8H8V8z"></path></svg>
            </span>
          </button>
        </div>
      </div>
    </div>
  </div>
</template>

<script setup lang="ts">
import { ref, onMounted, nextTick, watch, onUnmounted } from 'vue';
import { marked } from 'marked';
import DOMPurify from 'dompurify';
import { currentNodeInfo } from '@/stores/currentNodeStore';
import { aiMessageStore } from '@/stores/aiMessage';

// 配置marked
marked.setOptions({
  async: false,
  breaks: true,
  gfm: true
});

const aiMmgStore = aiMessageStore();
const currentNode = currentNodeInfo();

// Markdown格式化函数
const formatMessage = (content: string): string => {
  try {
    return DOMPurify.sanitize(marked.parse(content) as any);
  } catch (error) {
    console.error('Markdown解析错误:', error);
    return DOMPurify.sanitize(content);
  }
};

interface ChatMessage {
  id: string;
  type: 'user' | 'ai';
  content: string;
}

const props = defineProps({
  width: {
    type: Number,
    required: true
  },
  visible: {
    type: Boolean,
    required: true
  },
  initialMessages: {
    type: Array as () => string[],
    default: () => []
  }
});

const emit = defineEmits(['close', 'update:isAIOpen', 'messageSent', 'modelChanged']);

const chatInput = ref('');
const inputRef = ref<any>(null);
const streamButtonRef = ref<HTMLButtonElement | null>(null);
const modelSel = ref('deepseek-ai/DeepSeek-V3');
const isStreaming = ref(false);
const streamError = ref<string | null>(null);
const abortController = ref<AbortController | null>(null);
let currentAiMessageId: string | null = null;

const chatMessages = ref<ChatMessage[]>(
  props.initialMessages.map((msgStr, index) => {
    const { type, content } = parseInitialMessage(msgStr);
    return { id: `initial-${index}-${Date.now()}`, type, content };
  })
);

const parseInitialMessage = (msgStr: string): { type: 'user' | 'ai', content: string } => {
  const lowerMsgStr = msgStr.toLowerCase();
  let type: 'user' | 'ai' = 'ai';
  let content = msgStr.trim();

  const userPrefixes = ["你：", "user:"];
  const aiPrefixes = ["ai：", "assistant:"];

  for (const prefix of userPrefixes) {
    if (lowerMsgStr.startsWith(prefix)) {
      type = 'user';
      content = msgStr.substring(prefix.length).trim();
      break;
    }
  }
  
  if (type === 'ai') {
    for (const prefix of aiPrefixes) {
      if (lowerMsgStr.startsWith(prefix)) {
        type = 'ai';
        content = msgStr.substring(prefix.length).trim();
        break;
      }
    }
  }
  
  return { type, content };
};

const scrollToBottom = () => {
  nextTick(() => {
    const chatArea = document.querySelector('.ai-chat');
    if (chatArea) {
      chatArea.scrollTop = chatArea.scrollHeight;
    }
  });
};

const syncInputButtonHeight = () => {
  nextTick(() => {
    if (inputRef.value && inputRef.value.$el && streamButtonRef.value) {
      const inputEl = inputRef.value.$el.querySelector('.el-input__inner') as HTMLElement;
      const btnEl = streamButtonRef.value;
      if (inputEl && btnEl) {
        btnEl.style.height = `${inputEl.offsetHeight}px`;
      }
    }
  });
};

const updateAiMessageWithStreamData = (data: string) => {
  const aiMessageEntry = chatMessages.value.find(m => m.id === currentAiMessageId);
  if (aiMessageEntry) {
    // const formattedData = data.replace(/\\n/g, '\n');
    aiMessageEntry.content += data//formattedData;
    aiMmgStore.resposeMarkdon = aiMessageEntry.content;
    scrollToBottom();
  }
};

const updateFinalAiMessageWithStatus = (statusMessage: string, isErrorType: boolean) => {
  const aiMessageEntry = chatMessages.value.find(m => m.id === currentAiMessageId);
  const messageToDisplay = `${isErrorType ? '[错误: ' : '['}${statusMessage}${isErrorType ? ']' : ']'}`;

  if (aiMessageEntry) {
    if (aiMessageEntry.content === '' || !aiMessageEntry.content.includes(messageToDisplay)) {
      aiMessageEntry.content += (aiMessageEntry.content.endsWith('\n') || aiMessageEntry.content === '' ? '' : '\n') + messageToDisplay;
    }
  } else if (currentAiMessageId) {
    chatMessages.value.push({ id: currentAiMessageId, type: 'ai', content: messageToDisplay });
  } else {
    chatMessages.value.push({ id: `ai-status-${Date.now()}`, type: 'ai', content: messageToDisplay });
  }
  scrollToBottom();
};

const startStream = async () => {
  const currentcontent = currentNode.nodeMarkdown;
  const userInput = chatInput.value.trim();
  
  if (!userInput) {
    streamError.value = '请输入您的问题。';
    return;
  }

  isStreaming.value = true;
  streamError.value = null;
  abortController.value = new AbortController();
  
  chatMessages.value.push({ id: `user-${Date.now()}`, type: 'user', content: userInput });
  emit('messageSent', userInput);

  currentAiMessageId = `ai-${Date.now()}`;
  chatMessages.value.push({ id: currentAiMessageId, type: 'ai', content: '' });
  chatInput.value = '';
  scrollToBottom();

  try {
    const streamUrl = `http://localhost:8080/api/chat_t/stream_t`;
    const response = await fetch(streamUrl, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'Accept': 'text/event-stream',
        'satoken': localStorage.getItem("satoken")||"" // 添加 satoken
      },
      body: JSON.stringify({
        message: currentcontent + userInput,
        model: modelSel.value,
      }),
      signal: abortController.value.signal,
    });

    if (!response.ok) {
      throw new Error(`请求失败，状态码: ${response.status}`);
    }

    if (!response.body) {
      throw new Error('Response body is null');
    }

    const reader = response.body.getReader();
    const decoder = new TextDecoder('utf-8');
    let accumulatedChunk = '';

    while (true) {
      const { value, done } = await reader.read();
      if (done) break;

      accumulatedChunk += decoder.decode(value, { stream: true });
      let contentForThisPass = "";

      const doneSignalIndex = accumulatedChunk.indexOf("[DONE]");
      if (doneSignalIndex !== -1) {
        const partBeforeDone = accumulatedChunk.substring(0, doneSignalIndex);
        partBeforeDone.split('\n').forEach(line => {
          const trimmedLine = line.trim();
          if (trimmedLine.startsWith("data:")) {
            contentForThisPass += trimmedLine.substring(5);
          }
        });
        accumulatedChunk = '';
      } else {
        let searchStartIndex = 0;
        while (true) {
          const newlineIndex = accumulatedChunk.indexOf('\n', searchStartIndex);
          if (newlineIndex === -1) break;

          const line = accumulatedChunk.substring(searchStartIndex, newlineIndex).trim();
          if (line.startsWith("data:")) {
            contentForThisPass += line.substring(5);
          }
          searchStartIndex = newlineIndex + 1;
        }
        accumulatedChunk = accumulatedChunk.substring(searchStartIndex);
      }

      if (contentForThisPass) {
        updateAiMessageWithStreamData(contentForThisPass);
      }
    }
  } catch (err: any) {
    if (err.name !== 'AbortError') {
      console.error('Error in startStream:', err);
      streamError.value = `连接或处理错误: ${err.message || '未知错误'}`;
    }
  } finally {
    isStreaming.value = false;
    if (abortController.value) {
      abortController.value.abort();
      abortController.value = null;
    }
    scrollToBottom();
  }
};

const stopStreamUserAction = () => {
  if (isStreaming.value) {
    streamError.value = '用户主动终止对话';
    if (abortController.value) {
      abortController.value.abort();
    }
  }
};

const toggleStream = () => {
  if (isStreaming.value) {
    stopStreamUserAction();
  } else {
    startStream();
  }
};

const closePanel = () => {
  emit('close');
};

watch(modelSel, (newValue) => {
  emit('modelChanged', newValue);
});

watch(chatMessages, scrollToBottom, { deep: true });

onMounted(() => {
  syncInputButtonHeight();
  window.addEventListener('resize', syncInputButtonHeight);
});

onUnmounted(() => {
  window.removeEventListener('resize', syncInputButtonHeight);
  if (isStreaming.value && abortController.value) {
    abortController.value.abort();
  }
});
</script>

<style scoped>
.panel {
  position: relative;
  background-color: #f0f2f5;
  border-left: 1px solid #dcdfe6;
  transition: width 0.3s ease;
  overflow: hidden;
  flex-shrink: 0;
  height: 100%;
  display: flex;
  flex-direction: column;
}

.ai-header {
  padding: 15px;
  font-size: 16px;
  font-weight: bold;
  border-bottom: 1px solid #ddd;
  flex-shrink: 0;
}

.ai-chat {
  flex: 1;
  padding: 15px;
  overflow-y: auto;
  min-height: 0;
  background-color: #fff;
}

.chat-message-wrapper {
  margin-bottom: 10px;
}

.chat-message {
  padding: 8px 12px;
  border-radius: 6px;
  word-wrap: break-word;
}

.message-user {
  background-color: #d1e7dd;
  text-align: right;
  margin-left: auto;
  max-width: 80%;
}

.message-ai {
  background-color: #f8f9fa;
  border: 1px solid #e9ecef;
  max-width: 80%;
}

.message-content {
  margin: 0;
  font-family: inherit;
  line-height: 1.6;
  overflow-wrap: break-word;
  text-align: left;
}

.message-content :deep() h1,
.message-content :deep() h2,
.message-content :deep() h3,
.message-content :deep() h4,
.message-content :deep() h5,
.message-content :deep() h6 {
  margin-top: 0.5em;
  margin-bottom: 0.5em;
}

.message-content :deep() p {
  margin: 0.5em 0;
}

.message-content :deep() code {
  background-color: #f0f0f0;
  padding: 0.2em 0.4em;
  border-radius: 3px;
  font-family: monospace;
}

.message-content :deep() pre {
  background-color: #f5f5f5;
  padding: 0.5em;
  border-radius: 3px;
  overflow-x: auto;
}

.message-content :deep() blockquote {
  border-left: 3px solid #ddd;
  padding-left: 1em;
  color: #666;
  margin-left: 0;
}

.message-content :deep() a {
  color: #409eff;
  text-decoration: none;
}

.message-content :deep() a:hover {
  text-decoration: underline;
}

.message-content :deep() ul,
.message-content :deep() ol {
  padding-left: 1.5em;
}

.message-content :deep() li {
  margin-bottom: 0.25em;
}

.panel-content {
  flex-shrink: 0;
}

.ai-input {
  padding: 15px;
  border-top: 1px solid #ddd;
}

.input-group {
  display: flex;
  align-items: stretch;
}

.custom-change-btn {
  width: auto;
  min-width: 90px;
  margin-right: -1px;
}

.custom-change-btn .el-input__inner {
  border-radius: 4px 0 0 4px !important;
}

.custom-input {
  flex: 1;
}

.custom-input .el-input__inner {
  border-radius: 0 !important;
}

.stream-action-button {
  padding: 0 10px;
  background-color: #409eff;
  color: white;
  border: 1px solid #409eff;
  margin-left: -1px;
  cursor: pointer;
  display: flex;
  justify-content: center;
  align-items: center;
  transition: background-color 0.3s ease, transform 0.1s ease, border-color 0.3s ease;
  flex-shrink: 0;
  border-radius: 0 4px 4px 0;
}

.stream-action-button:hover {
  opacity: 0.9;
  background-color: #66b1ff;
  border-color: #66b1ff;
}

.stream-action-button:active {
  transform: scale(0.95);
}

.stream-action-button.streaming {
  background-color: #ff4d4f;
  border-color: #ff4d4f;
}

.stream-action-button.streaming:hover {
  background-color: #ff7875;
  border-color: #ff7875;
}

.stream-action-button svg {
  width: 18px;
  height: 18px;
}

.custom-input:focus-within {
  z-index: 1;
}

.stream-action-button:focus {
  z-index: 1;
}

.button-right-close {
  position: absolute;
  top: 10px;
  right: 15px;
  background-color: rgb(147, 187, 187);
  z-index: 10;
}

.stream-error-message {
  color: #ff4d4f;
  margin-top: 10px;
  padding: 8px;
  background-color: rgba(255, 77, 79, 0.1);
  border: 1px solid rgba(255, 77, 79, 0.3);
  border-radius: 4px;
  font-size: 0.9em;
}
</style>